package com.jiajia.study.chapter01.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;

/**
 * selector 模式 - 单线程
 * @author zjiajia
 * @date 2024/7/5 12:06
 */
public class TestServerV3 {
    public static void main(String[] args) throws IOException {

        Selector selector = Selector.open();
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);

        serverSocketChannel.bind(new InetSocketAddress(8888));

        SelectionKey selectionKey = serverSocketChannel.register(selector, 0, null);
        // 关注 accept 事件
        selectionKey.interestOps(SelectionKey.OP_ACCEPT);
        while(true){
            /**
             * 阻塞，等待事件的出发
             */
            selector.select();

            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while(iterator.hasNext()){
                SelectionKey key = iterator.next();
                iterator.remove();
                // 处理连接
                if(key.isAcceptable()){
                    serverSocketChannel = (ServerSocketChannel)key.channel();
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);
                    // 新的连接注册到 selector 上面去
                    SelectionKey socketSelectionKey = socketChannel.register(selector, 0, null);
                    socketSelectionKey.interestOps(SelectionKey.OP_READ);

                }else if(key.isReadable()){
                    SocketChannel socketChannel = (SocketChannel)key.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(32);
                    /**
                     * 正常断开，会触发一个读事件，此时 read 读取到的结果是  -1
                     */
                    try{

                        int read = socketChannel.read(byteBuffer);
                        if(read == -1){
                            // 取消，从监听的集合中移除掉
                            key.cancel();
                        }else {
                            // 进行数据的处理，切换成读模式
                            byteBuffer.flip();
                            System.out.println(StandardCharsets.UTF_8.decode(byteBuffer));
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                        /**
                         * 强制断开，需要取消 selector 的监听
                         */
                        key.cancel();
                    }

                }
            }
        }

    }
}
